#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/device/class.h>

#include "led_drv.h"

struct gpio_desc * led1,*led2;
int major;
struct class *led_class;

int file_open(struct inode * ind, struct file * fp){
    printk("[%s %d]:[%s]\n", __FILE__, __LINE__, __func__);
    return 0;
}

int file_release(struct inode * ind, struct file * fp){
    printk("[%s %d]:[%s]\n", __FILE__, __LINE__, __func__);
    return 0;
}

long file_ioctl(struct file * fp, unsigned int cmd, unsigned long args){
    int get_value;
    printk("[%s %d]:[%s] cmd=[%d],args=[%ld]\n", __FILE__, __LINE__, __func__, cmd, args);
    if(cmd == LED1_SET){
        gpiod_set_value(led1, args);
        return 0;
    }
    if(cmd == LED2_SET){
        gpiod_set_value(led2, args);
        return 0;
    }

    if(cmd == LED1_GET)
        get_value = gpiod_get_value(led1);
    else if(cmd == LED2_GET)
        get_value = gpiod_get_value(led2);
    else
        return -1;
    copy_to_user((int*)args, &get_value, sizeof(int));
    return 0;
}

struct file_operations fops={
    .open = file_open,
    .release = file_release,
    .unlocked_ioctl = file_ioctl,
};

int led_probe(struct platform_device * pdev){
    struct device * dev;
    printk("[%s %d]:[%s]\n", __FILE__, __LINE__, __func__);
    led1 = gpiod_get_from_of_node(pdev->dev.of_node, "led-gpios",0, GPIOD_OUT_LOW,NULL);
    led2 = gpiod_get_from_of_node(pdev->dev.of_node, "led-gpios",1, GPIOD_OUT_LOW,NULL);
    
    gpiod_set_value(led1, 1);
    gpiod_set_value(led2, 1);

    //
    major = register_chrdev(0, "led_drv", &fops);
    if(major < 0){
        printk("register_chrdev failed\n");
        return major;
    }
    printk("led_drv major = %d\n", major);
    //
    led_class = class_create(THIS_MODULE, "led_drv");
    if(IS_ERR(led_class)){
        unregister_chrdev(major, "led_drv");
        return PTR_ERR(led_class);
    }
    dev = device_create(led_class, NULL, MKDEV(major, 0), NULL, "led_drv");
    if(IS_ERR(dev)){
        class_destroy(led_class);
        unregister_chrdev(major, "led_drv");
        return PTR_ERR(dev);
    }   
    // 设备创建成功
    printk("led_drv device_create success\n");
    
    return 0;
}

int led_remove(struct platform_device * pdev){
    printk("[%s %d]:[%s]\n", __FILE__, __LINE__, __func__);
    // gpiod_set_value(led1, 0);
    // gpiod_set_value(led2, 0);

    gpiod_put(led1);
    gpiod_put(led2);

    //
    device_destroy(led_class, MKDEV(major, 0));
    class_destroy(led_class);
    unregister_chrdev(major, "led_drv");
    // 设备销毁成功
    printk("led_drv device_destroy success\n");

    return 0;
}

const struct of_device_id of_match_table[] = {
    {.compatible = "zr,myled"},
    {},
};

struct platform_driver led_drv = {
    .driver = {
        .name = "led_drv",
        .owner = THIS_MODULE,
        .of_match_table = of_match_table,
    },
    .probe = led_probe,
    .remove = led_remove
};


module_platform_driver(led_drv);
MODULE_LICENSE("GPL");